package com.linewell.export.util;

import java.io.*;
import java.lang.reflect.Array;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Title: PubUtils
 * @description:
 * @author: zz.pzq@qq.com
 * @since: 2020年09月22日 19:15
 */
public class PubUtils {

    /** yyyy-MM-dd HH:mm:ss */
    public static final DateTimeFormatter YYYY_MM_DD_HHMMSS = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    /**
     * 东8区
     */
    public static final String UTC_EIGHT = "+8";


    // 校验方法start --------------------------------------------------------------
    // --------------------------------------------------------------------------

    /**
     * 判空操作
     *
     * @param obj 对象
     * @return [true|false]
     */
    public static boolean isEmpty(Object obj) {
        if (obj == null) {
            return true;
        }
        if (obj instanceof CharSequence) {
            return 0 == ((CharSequence) obj).length();
        }else if(obj.getClass().isArray()){
            return 0 == Array.getLength(obj);
        }else if (obj instanceof Collection<?>) {
            return 0 == ((Collection<?>) obj).size();
        }else if(obj instanceof Map<?, ?>) {
            return 0 == ((Map<?, ?>) obj).size();
        }else if (obj instanceof Dictionary<?, ?>) {
            return 0 == ((Dictionary<?, ?>) obj).size();
        }else {
            return false;
        }
    }

    /**
     * 判不为空操作
     *
     * @param obj 对象
     * @return [true|false]
     */
    public static boolean isNotEmpty (Object obj){
        return !isEmpty(obj);
    }

    /**
     * 判断是否为空白字符
     *
     * @param c int
     * @return true 是空白符 | false不是空白符
     */
    public static boolean isBlank(int c) {
        return Character.isWhitespace(c) || Character.isSpaceChar(c) || c == '\ufeff' || c == '\u202a';
    }

    /**
     * 判断不为空白字符
     *
     * @param c int
     * @return true 是空白符 | false不是空白符
     */
    public static boolean isNotBlank(int c) {
        return !isBlank(c);
    }

    /**
     * 判断是否为空白字符
     *
     * @param c 字符
     * @return true 是空白符 | false不是空白符
     */
    public static boolean isBlank(char c) {
        return isBlank((int) c);
    }

    /**
     * 判断是不为空白字符
     *
     * @param c 字符
     * @return true 是空白符 | false不是空白符
     */
    public static boolean isNotBlank(char c) {
        return !isBlank(c);
    }

    /**
     * 判断是否为空白字符串
     *
     * @param str 字符串
     * @return true 是空白字符串 | false不是空白字符串
     */
    public static boolean isBlank(CharSequence str) {
        if (null == str || str.length() < 1) {
            return true;
        }
        for (int i = 0; i < str.length(); i++) {
            if (!isBlank(str.charAt(i))){
                return false;
            }
        }
        return true;
    }

    /**
     * 判断不为空白字符串
     *
     * @param str 字符串
     * @return true 是空白字符串 | false不是空白字符串
     */
    public static boolean isNotBlank(CharSequence str) {
        return !isBlank(str);
    }

    // 校验方法end ---------------------------------------------------------------
    // --------------------------------------------------------------------------

    /***************************************************************************/

    // 常用方法start -------------------------------------------------------------
    // -------------------------------------------------------------------------

    /***************************************************************************/

    // 字符串操作 ----------------------------------------------------------------
    // -------------------------------------------------------------------------

    /**
     * 获取uuid 含-
     * @return 字符串
     */
    public static String getUuid(){
        return UUID.randomUUID().toString();
    }

    /**
     * 获取uuid 不含-
     * @return 字符串
     */
    public static String getUUID() {
        return getUuid().replaceAll("-", "");
    }

    // 字符串操作 ----------------------------------------------------------------
    // -------------------------------------------------------------------------

    /****************************************************************************/

    // 对象 --------------------------------------------------------------------
    // -------------------------------------------------------------------------
    /**
     * 获取对象的类型，不是数组返回null
     *
     * @param obj 对象
     * @return 对象的类型
     */
    public static Class<?> getComponentType(Object obj) {
        return null == obj ? null : obj.getClass().getComponentType();
    }

    /**
     * 获取元素类型,不是数组返回null
     *
     * @param objClass 类
     * @return 数组元素类型
     */
    public static Class<?> getComponentType(Class<?> objClass) {
        return null == objClass ? null : objClass.getComponentType();
    }
    // 对象 --------------------------------------------------------------------
    // -------------------------------------------------------------------------

    /***************************************************************************/

    // 数组操作 -----------------------------------------------------------------
    // -------------------------------------------------------------------------
    /**
     * 包装转换
     * @param arr int[]
     * @return Integer[]
     */
    public static Integer[] wrapIntArr(int[] arr) {
        return Arrays.stream(arr).boxed().toArray(Integer[]::new);
    }

    /**
     * 拆包转换
     * @param arr Integer[]
     * @return int[]
     */
    public static int[] unwrapIntegerArr(Integer[] arr) {
        return Arrays.stream(arr).mapToInt(Integer::valueOf).toArray();
    }

    /**
     * int[] -> list<Integer>
     * @param arr int[]
     * @return list
     */
    public static List<Integer> toList(int[] arr) {
        return Arrays.stream(arr).boxed().collect(Collectors.toList());
    }

    /**
     * 数组
     * @param arr 数组
     * @param format 拼接标识
     * @return 字符串
     */
    public static <T> String join(T[] arr, String format) {
        if (isEmpty(arr)) {
            return "";
        }
        StringBuilder sb = new StringBuilder();
        sb.append(arr[0]);
        if (arr.length  == 1) {
            return sb.toString();
        }
        for (int i = 1; i < arr.length; i++) {
            sb.append(format).append(arr[i]);
        }
        return sb.toString();
    }

    /**
     * 数组
     * @param arr 数组
     * @return 字符串
     */
    public static <T> String join(T[] arr) {
        return join(arr,",");
    }

    /**
     * 数组
     * @param arr 数组
     * @param format 拼接标识
     * @return 字符串
     */
    public static String join(int[] arr, String format) {
        return join(wrapIntArr(arr), format);
    }

    /**
     * 数组
     * @param arr 数组
     * @return 字符串
     */
    public static String join(int[] arr) {
        return join(arr, ",");
    }

    /**
     * 数组去重
     *
     * @param t 数组
     * @param <T> 泛型
     * @return T[]
     */
    public static <T> T[] distinct(T[] t) {
        if (isEmpty(t)) {
            return t;
        }
        Set<T> set = new HashSet<>();
        Collections.addAll(set, t);
        return set.toArray(newArray(t, set.size()));
    }

    /**
     * 创建指定类型、长度的数组
     * @param t 指定类型数组
     * @param length 指定长度
     * @param <T> 泛型
     * @return T[]
     */
    public static <T> T[] newArray(T[] t, int length) {
        return newArray(getComponentType(t), length);
    }

    /**
     * 创建指定类型的数组
     *
     * @param componentType 类型
     * @param length        长度
     * @param <T>           泛型
     * @return 改类型数组
     */
    @SuppressWarnings("unchecked")
    public static <T> T[] newArray(Class<?> componentType, int length) {
        return (T[]) Array.newInstance(componentType, length);
    }

    /**
     * 数组过滤
     * @param arr 数组
     * @param filter 过滤方式【需实现】
     * @param <T> 泛型
     * @return T[]
     */
    public static <T> T[] filter(T[] arr, PubFilter<T> filter) {
        if (isEmpty(arr)) {
            return arr;
        }
        List<T> list = new ArrayList<>();
        for (T t : arr) {
            if (filter.filter(t)){
                continue;
            }
            list.add(t);
        }
        return list.toArray(newArray(arr, list.size()));
    }

    /**
     * 默认过滤空
     *
     * @param arr 数组
     * @param <T> 泛型
     * @return T[]
     */
    public static <T> T[] filter(T[] arr) {
        return filter(arr, PubUtils::isEmpty);
    }

    /**
     * 数组转list
     * 可进行增删操作，防止出现 UnsupportedOperationException
     *
     * @param arr 数组
     * @param <T> 泛型
     * @return list
     */
    public static <T> List<T> toList(T[] arr) {
        return new ArrayList<>(Arrays.asList(arr));
    }

    /**
     * 数组追加元素
     * 数组为空时，抛出空指针异常；
     * 数组类型和参数类型不一致 抛出异常
     * @param arr 数组
     * @param t 参数
     * @param <T> 泛型
     * @return T[]
     */
    @SafeVarargs
    public static <T> T[] add(T[] arr, T... t) {
        Objects.requireNonNull(arr);
        if (getComponentType(arr) != getComponentType(t)){
            // 数组组件类型和参数组件类型不一致
            throw new SecurityException("array[" + getComponentType(arr) + "] and parameter[" + getComponentType(t) + "] are inconsistent");
        }
        List<T> list = toList(arr);
        Collections.addAll(list, t);
        return list.toArray(newArray(arr, list.size()));
    }

    /**
     * 数组删除元素
     * 数组为空时，抛出空指针异常；
     * 数组类型和参数类型不一致 抛出异常
     * @param arr 数组
     * @param t 参数
     * @param <T> 泛型
     * @return T[]
     */
    @SafeVarargs
    public static <T> T[] remove(T[] arr, T... t) {
        Objects.requireNonNull(arr);
        if (getComponentType(arr) != getComponentType(t)){
            // 数组组件类型和参数组件类型不一致
            throw new SecurityException("array[" + getComponentType(arr) + "] and parameter[" + getComponentType(t) + "] are inconsistent");
        }
        return filter(arr, s -> {
            for (T t1 : t) {
                if (t1 == s) {
                    return true;
                }
            }
            return false;
        });
    }

    /**
     * 数组删除指定索引元素
     *
     * @param arr 数组
     * @param index 索引
     * @param <T> 泛型
     * @return T[]
     */
    public static <T> T[] remove(T[] arr, int index) {
        Objects.requireNonNull(arr);
        if (index < 0 || index > arr.length - 1) {
            throw new ArrayIndexOutOfBoundsException("the array index max[" + (arr.length - 1) + "],parameter index[" + index + "] should not less than or greater than [" + (arr.length - 1) + "]");
        }
        List<T> list = toList(arr);
        list.remove(index);
        return list.toArray(newArray(arr, list.size()));
    }

    /**
     * 判断数组是否存在元素
     *
     * @param arr 数组
     * @param t 元素
     * @return 索引
     */
    public static int indexOf(Object[] arr,Object t) {
        if (isNotEmpty(arr)) {
            for (int i = 0; i < arr.length; i++) {
                if (t == arr[i]) {
                    return i;
                }
            }
        }
        return -1;
    }

    /**
     * 判断数组是否存在元素 从后往前
     *
     * @param arr 数组
     * @param t 元素
     * @return 索引
     */
    public static int lastIndexOf(Object[] arr, Object t) {
        if (isNotEmpty(arr)) {
            for (int i = arr.length -1 ; i > 0 ; i--) {
                if (t == arr[i]) {
                    return i;
                }
            }
        }
        return -1;
    }

    /**
     * 判断数组是否存在元素忽略大小写
     *
     * @param arr 数组
     * @param t 元素
     * @return 索引
     */
    public static int indexOfIgnoreCase(Object[] arr,Object t) {
        if (isNotEmpty(arr)) {
            for (int i = 0; i < arr.length; i++) {
                if (isNotEmpty(arr[i]) && isNotEmpty(t)) {
                    if (arr[i].toString().equalsIgnoreCase(t.toString())){
                        return i;
                    }
                }else {
                    if (arr[i] == t) {
                        return i;
                    }
                }
            }
        }
        return -1;
    }

    /**
     * 数组包含元素判断
     * @param arr 数组
     * @param t 元素
     * @return boolean
     */
    public static boolean contains(Object[] arr, Object t) {
        return indexOf(arr, t) > -1;
    }

    // 数组操作 -----------------------------------------------------------------
    // -------------------------------------------------------------------------

    /***************************************************************************/

    // 集合类操作 ---------------------------------------------------------------
    // -------------------------------------------------------------------------

    /**
     * list -> arr
     * @param list list<Integer>
     * @return int[]
     */
    public static int[] toArray(List<Integer> list) {
        return list.stream().mapToInt(Integer::valueOf).toArray();
    }

    /**
     * 集合拼接成字符串
     *
     * @param coll 集合
     * @param format 拼接标识
     * @return 字符串
     */
    public static String join(Collection<?> coll, String format) {
        if (coll == null || coll.size() < 1) {
            return "";
        }
        StringBuilder sb = new StringBuilder();
        Iterator<?> iterator = coll.iterator();
        sb.append(iterator.next());
        while (iterator.hasNext()) {
            sb.append(format).append(iterator.next());
        }
        return sb.toString();
    }

    /**
     * 集合拼接成字符串
     *
     * @param coll 集合
     * @return 字符串
     */
    public static String join(Collection<?> coll) {
        return join(coll,",");
    }

    /**
     * 集合过滤，过滤为true的元素
     *
     * @param coll 集合
     * @param filter 过滤条件 【需实现】
     * @param <T> 泛型
     * @return 集合
     */
    public static <T> Collection<T> filter(Collection<T> coll, PubFilter<T> filter) {
        if (isEmpty(coll)) {
            return coll;
        }
        coll.removeIf(filter::filter);
        return coll;
    }

    /**
     * 集合过滤，过滤为true的元素
     *
     * @param coll 集合
     * @param <T> 泛型
     * @return 集合
     */
    public static <T> Collection<T> filter(Collection<T> coll) {
        return filter(coll, PubUtils::isEmpty);
    }

    // 集合类操作 ---------------------------------------------------------------
    // -------------------------------------------------------------------------

    /***************************************************************************/

    // IO流操作-----------------------------------------------------------------
    // -------------------------------------------------------------------------

    /**
     * 获取文件对象
     *
     * @param filepath 路径
     * @return 文件对象
     */
    private static File getFile(String filepath) {
        if (isEmpty(filepath)) {
            throw new RuntimeException("路径不能为空！");
        }
        return new File(filepath);
    }


    /**
     * 将文件获取为字符串
     *
     * @param filePath 文件路径
     * @return 字符串
     */
    public static String getFile2String(String filePath, Charset charset) {
        File file = getFile(filePath);
        if (!file.exists()){
            throw new RuntimeException("文件不存在！");
        }
        StringBuilder sb = new StringBuilder();
        InputStream is = null;
        InputStreamReader reader = null;
        BufferedReader br = null;
        try {
            is = new FileInputStream(file);
            reader = new InputStreamReader(is, charset.code);
            br = new BufferedReader(reader);
            String s = br.readLine();
            if (s == null) {
                return "";
            }
            sb.append(s);
            String newLine = getNewLine();
            while (null != (s = br.readLine())) {
                sb.append(newLine).append(s);
            }
            br.close();
            reader.close();
            is.close();
        } catch (FileNotFoundException e) {
            throw new RuntimeException("文件未找到！");
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                if (br != null) {
                    br.close();
                }
                if (reader != null) {
                    reader.close();
                }
                if (is != null) {
                    is.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return sb.toString();
    }

    /**
     * 将文件获取为byte数组
     *
     * @param filePath 文件路径
     * @return byte[]数组
     */
    public static byte[] getFile2bytes(String filePath) {
        File file = getFile(filePath);
        if (!file.exists()) {
            throw new RuntimeException("文件不存在！");
        }
        long fileSize = file.length();
        if (fileSize > Integer.MAX_VALUE) {
            throw new RuntimeException("文件过大，请选择其他方式获取。");
        }
        try {
            FileInputStream fi = new FileInputStream(file);
            byte[] buffer = new byte[(int) fileSize];
            int offset = 0;
            int numRead;
            while (offset < buffer.length && (numRead = fi.read(buffer, offset, buffer.length - offset)) >= 0) {
                offset += numRead;
            }
            // 确保所有数据均被读取
            if (offset != buffer.length) {
                throw new IOException("Could not completely read file " + file.getName());
            }
            fi.close();
            return buffer;
        }catch ( IOException e) {
            throw new RuntimeException("文件获取异常！" , e);
        }

    }

    /**
     * NIO way
     *
     * @param filepath 文件路径
     * @return byte[]
     *
     */
    public static byte[] getFile2byteArray(String filepath) {
        File f = getFile(filepath);
        if (!f.exists()) {
           throw new RuntimeException("文件未找到：" + filepath);
        }

        FileChannel channel = null;
        FileInputStream fs = null;
        try {
            fs = new FileInputStream(f);
            channel = fs.getChannel();
            ByteBuffer byteBuffer = ByteBuffer.allocate((int) channel.size());
            channel.read(byteBuffer);
            return byteBuffer.array();
        } catch (IOException e) {
            throw new RuntimeException("IO流操作失败！", e);
        } finally {
            try {
                if (channel != null) {
                    channel.close();
                }
                if (fs != null) {
                    fs.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * Mapped File way MappedByteBuffer 可以在处理大文件时，提升性能
     *
     * @param filename 文件名
     * @return byte[]
     */
    public static byte[] getBigFile(String filename){
        if (isEmpty(filename)) {
            throw new RuntimeException("文件路径不能为空！");
        }

        FileChannel fc = null;
        try {
            fc = new RandomAccessFile(filename, "r").getChannel();
            MappedByteBuffer byteBuffer = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size()).load();
            byte[] result = new byte[(int) fc.size()];
            if (byteBuffer.remaining() > 0) {
                byteBuffer.get(result, 0, byteBuffer.remaining());
            }
            return result;
        } catch (IOException e) {
            throw new RuntimeException("IO流操作失败！", e);
        } finally {
            try {
                if (null != fc) {
                    fc.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * the traditional io way
     *
     * @param filepath 文件路径
     * @return byte数组
     */
    public static byte[] getFileToBytes(String filepath) {
        File f = getFile(filepath);
        if (!f.exists()) {
            throw new RuntimeException("文件路径未找到：" + filepath);
        }
        ByteArrayOutputStream bos = new ByteArrayOutputStream((int) f.length());
        BufferedInputStream in = null;
        try {
            in = new BufferedInputStream(new FileInputStream(f));
            int buf_size = 1024;
            byte[] buffer = new byte[buf_size];
            int len = 0;
            while (-1 != (len = in.read(buffer, 0, buf_size))) {
                bos.write(buffer, 0, len);
            }
            return bos.toByteArray();
        } catch (IOException e) {
            throw new RuntimeException("IO流操作失败",e);
        } finally {
            try {
                bos.close();
                if (in != null) {
                    in.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 判断文件是否存在
     *
     * @param filePath 文件路径
     * @return boolean
     */
    public static boolean isExists(String filePath) {
        if (isEmpty(filePath)) {
            return false;
        }
        return new File(filePath).exists();
    }

    /**
     * 判断是否为文件夹
     *
     * @param filePath 文件路径
     * @return boolean
     */
    public static boolean isDirectory(String filePath) {
        if (isEmpty(filePath)){
            return false;
        }
        return new File(filePath).isDirectory();
    }

    /**
     * 创建文件及目录
     *
     * @param filePath 路径
     * @return boolean
     */
    public static boolean mkdirAndFile(String filePath) {
        return mkdirAndFile(getFile(filePath));
    }

    public static boolean mkdirAndFile(File file) {
        try {
            if (!file.exists()) {
                String path = file.getAbsolutePath();
                String[] pathArr = path.split("\\\\");
                if (pathArr[pathArr.length - 1].contains(".")) {
                    File parentFile = file.getParentFile();
                    if (!parentFile.exists()) {
                        boolean b = parentFile.mkdirs();
                        if (!b) {
                            throw new RuntimeException("文件父目录创建失败");
                        }
                    }
                } else {
                    return file.mkdirs();
                }
                return file.createNewFile();
            }
        }catch (IOException e) {
            throw new RuntimeException("文件或目录创建失败", e);
        }
        return false;
    }

    /**
     * 转文件
     *
     * @param fileData 字节数组
     * @param filepath 路径
     * @param isCover 是否覆盖
     * @return boolean
     */
    public static boolean bytes2File(byte[] fileData, String filepath,boolean isCover) {
        if (isEmpty(fileData)) {
            return false;
        }
        if (isEmpty(filepath)){
            throw new RuntimeException("路径不能为空");
        }
        File file = new File(filepath);
        boolean exists = file.exists();
        if (exists && !isCover) {
            throw new RuntimeException("文件已存在！");
        }
        File parentFile = file.getParentFile();
        if (!parentFile.exists()) {
            boolean b = mkdirAndFile(parentFile);
            if (!b) {
                return false;
            }
        }
        OutputStream bos = null;
        OutputStream fos = null;
        try {
            fos = new FileOutputStream(file);
            bos = new BufferedOutputStream(fos);
            bos.write(fileData);
            return true;
        }catch (IOException e) {
            throw new RuntimeException("IO流操作失败", e);
        }finally {
            try{
                if (bos != null) {
                    bos.close();
                }
                if (null != fos) {
                    fos.close();
                }
            }catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public static boolean bytes2File(byte[] fileData, String filepath) {
        return bytes2File(fileData, filepath, true);
    }

    public static boolean bytesToFile(byte[] fileData, String filepath) {
        if (isEmpty(filepath)) {
            throw new RuntimeException("路径不能为空！");
        }
        Path path = Paths.get(filepath);
        try {
            Files.write(path, fileData);
            return true;
        }catch (IOException e) {
            throw new RuntimeException("IO操作异常", e);
        }
    }
    // IO流操作-----------------------------------------------------------------
    // -------------------------------------------------------------------------

    /***************************************************************************/

    // 系统级操作 ---------------------------------------------------------------
    // -------------------------------------------------------------------------

    /**
     * 获取系统名称
     *
     * @return 系统名称
     */
    public static String getOsName(){
        return System.getProperty("os.name").toLowerCase();
    }

    /**
     * 获取系统换行符
     *
     * @return 字符串
     */
    public static String getNewLine() {
        String os = getOsName();
        return os.contains("windows") ? "\r\n" : "\n";
    }

    // 系统级操作 ---------------------------------------------------------------
    // -------------------------------------------------------------------------

    /***************************************************************************/

    // 时间操作-----------------------------------------------------------------
    // ------------------------------------------------------------------------

    /**
     * 时间格式转毫秒时间戳
     *
     * @param dateTime 时间
     * @param formatter 时间格式
     * @return 毫秒时间戳
     */
    public static long toMillisecondsTimestamp(String dateTime, DateTimeFormatter formatter) {
        return LocalDateTime.parse(dateTime, formatter).toInstant(ZoneOffset.of(UTC_EIGHT)).toEpochMilli();
    }
    /**
     * 时间格式转毫秒时间戳
     * 默认格式yyyy-MM-dd HH:mm:ss
     *
     * @param dateTime 时间
     * @return 毫秒时间戳
     */
    public static long toMillisecondsTimestamp(String dateTime) {
        return toMillisecondsTimestamp(dateTime, YYYY_MM_DD_HHMMSS);
    }

    /**
     * 时间格式转秒时间戳
     *
     * @param dateTime 时间
     * @param formatter 时间格式
     * @return 秒时间戳
     */
    public static long toSecondsTimestamp(String dateTime, DateTimeFormatter formatter) {
        return LocalDateTime.parse(dateTime, formatter).toEpochSecond(ZoneOffset.of(UTC_EIGHT));
    }

    /**
     * 时间格式转秒时间戳
     * 默认格式yyyy-MM-dd HH:mm:ss
     *
     * @param dateTime 时间
     * @return 秒时间戳
     */
    public static long toSecondsTimestamp(String dateTime) {
        return toSecondsTimestamp(dateTime, YYYY_MM_DD_HHMMSS);
    }

    /**
     * 毫秒时间戳转LocalDateTime
     *
     * @param milliseconds 时间戳
     * @return 毫秒时间戳
     */
    public static LocalDateTime toLocalDateTime(long milliseconds) {
        return Instant.ofEpochMilli(milliseconds).atZone(ZoneOffset.ofHours(Digit.EIGHT.value)).toLocalDateTime();
    }

    /**
     * 格式化时间
     *
     * @param localDateTime 时间对象
     * @param dtf 格式
     * @return 时间
     */
    public static String toFormatTime(LocalDateTime localDateTime, DateTimeFormatter dtf) {
        return localDateTime.format(dtf);
    }

    /**
     * localDateTime转Date
     * @param localDateTime 时间对象
     * @return date格式
     */
    public static Date toDate(LocalDateTime localDateTime) {
        return Date.from(localDateTime.toInstant(ZoneOffset.of(UTC_EIGHT)));
    }

    /**
     * date 转 localDateTime
     * @param date date时间
     * @return LocalDateTime 时间
     */
    public static LocalDateTime toLocalDateTime(Date date) {
        return date.toInstant().atOffset(ZoneOffset.of(UTC_EIGHT)).toLocalDateTime();
    }

    /**
     * 时间戳格式化为指定格式时间
     *
     * @param millis 毫秒级时间戳
     * @param dtf 时间格式
     * @return 时间
     */
    public static String getTime(long millis, DateTimeFormatter dtf) {
        return toFormatTime(toLocalDateTime(millis), dtf);
    }

    /**
     * 时间戳格式化为默认yyyy-MM-ss HH:mm:ss格式时间
     *
     * @param mills 毫秒级时间戳
     * @return 时间
     */
    public static String getTime(long mills) {
        return getTime(mills, YYYY_MM_DD_HHMMSS);
    }

    /**
     * 以指定时间格式获取当前时间
     *
     * @param dtf 时间格式
     * @return 当前时间
     */
    public static String getCurrentTime(DateTimeFormatter dtf) {
        return getTime(System.currentTimeMillis(), dtf);
    }

    /**
     * 获取当前时间
     * 默认格式 yyyy-MM-dd HH:mm:ss
     *
     * @return 当前时间
     */
    public static String getCurrentTime() {
        return getTime(System.currentTimeMillis());
    }
    // 常用方法end -------------------------------------------------------------
    // -------------------------------------------------------------------------

    /**
     * 过滤接口
     */
    public interface PubFilter<T> {
        /**
         * 通用过滤方法
         * @param t 泛型
         * @return boolean
         */
        boolean filter(T t);
    }

    public enum Digit {
        ONE(1),
        TWO(2),
        THREE(3),
        FOUR(4),
        FIVE(5),
        SIX(6),
        SEVEN(7),
        EIGHT(8),
        NINE(9),
        ZERO(0);

        private final int value;

        Digit(int value) {
            this.value = value;
        }

        public int getValue() {
            return value;
        }
    }

    public enum Charset {

        GBK("GBK"),
        UTF8("UTF-8"),
        UTF16("UTF-16"),
        GB2312("GB2312"),
        ISO88591("ISO-8859-1");

        private final String code;

        Charset(String code){
            this.code = code;
        }

        public String getCode() {
            return this.code;
        }
    }
}
